package com.csnf.util;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * jdbc 工具类
 */
public class JdbcUtil {
    // 数据库连接信息  对应jdbc.properties
    private static String driverClassName;
    private static String url;
    private static String username;
    private static String password;
    protected static Logger logger = LogManager.getLogger(JdbcUtil.class);// 日志

    static {
        // 加载配置文件
        InputStream resAsStream = JdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties prop = new Properties();// 创建属性对象
        try {
            prop.load(resAsStream);
            driverClassName = prop.getProperty("driverClassName");
            url = prop.getProperty("url");
            username = prop.getProperty("username");
            password = prop.getProperty("password");
            logger.info("加载数据库配置文件成功");
            Class.forName(driverClassName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (null != resAsStream) {
                resAsStream.close();// 关闭流
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     *
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    /**
     * 获取预编译的Statement对象
     *
     * @param conn   数据库连接
     * @param sql    sql语句
     * @param params 对应参数
     * @return
     * @throws SQLException
     */
    public static PreparedStatement getPreparedStatement(Connection conn, String sql, Object... params) throws SQLException {
        PreparedStatement ps = conn.prepareStatement(sql);// 预编译sql，减少sql执行
        ParameterMetaData pmd = ps.getParameterMetaData();// 获取参数的元数据
        int paramCount = pmd.getParameterCount();// 参数个数
        // 去掉 params 中的null
        List<Object> values = nonNullParams(params);
        if (values.size() == paramCount) {// 判断参数是否为空
            for (int i = 0; i < paramCount; i++) {
                ps.setObject(i + 1, values.get(i));// 设置参数
            }
        }
        return ps;
    }

    /**
     * 关闭资源
     *
     * @param closeables 连接、预处理、结果集
     */
    public static void close(AutoCloseable... closeables) {
        if (null != closeables && closeables.length > 0) {
            for (AutoCloseable closeable : closeables) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 通过反射机制，将结果集转换为对象
     *
     * @param rs
     * @param tClass
     * @return
     * @throws Exception
     */
    public static <T> T invokeObject(ResultSet rs, Class<T> tClass) throws Exception {
        ResultSetMetaData md = rs.getMetaData();
        int count = md.getColumnCount();
        T t = tClass.getDeclaredConstructor().newInstance();
        for (int i = 1; i <= count; i++) {
            String columnName = md.getColumnName(i);
            String labelName = md.getColumnLabel(i);
            columnName = columnName.equals(labelName) ? columnName : labelName;
            Field field = tClass.getDeclaredField(columnName);
            field.setAccessible(true);
            Object value = rs.getObject(columnName);
            if(field.getType()== Date.class && value instanceof String ){
                value=DateUtil.parseDate((String) value,"yyyy-MM-dd");
            }
            field.set(t, value);
        }
        return t;
    }



    private static List<Object> nonNullParams(Object... params) {
        List<Object> list = new ArrayList<>();
        if (null == params) {
            return list;
        }
        for (Object param : params) {
            if (null != param) {
                list.add(param);
            }
        }
        return list;
    }
}
